package com.paic.mhis.hcpms.common.mathCal;

import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;

/**
 * 
 * @author  
 *
 */
public class MathExtendsUtil{
	
	final static BigDecimal TWO = BigDecimal.ONE.add(BigDecimal.ONE);

	/**
	 * 总和
	 * @param data
	 * @return
	 */
	public static BigDecimal getSum(List<BigDecimal> data){
		BigDecimal _d = BigDecimal.ZERO;
		if(data == null || data.size() == 0) 
			return _d;
		for (BigDecimal _b : data) {
			if(_b!=null){
				_d=_d.add(_b);
			}
		}
		return _d;
	}
	
	/**
	 * 总和
	 * @param data
	 * @return
	 */
	public static BigDecimal getSum(BigDecimal ... data){
		BigDecimal _d = BigDecimal.ZERO;
		if(data == null || data.length == 0) 
			return _d;
		for (BigDecimal _b : data) {
			if(_b!=null){
				_d=_d.add(_b);
			}
		}
		return _d;
	}
	
	/**
	 * 平均值
	 * @param data
	 * @return
	 */
	public static BigDecimal getAverage(List<BigDecimal> data){
		BigDecimal _d = BigDecimal.ZERO;
		if(data == null || data.size() == 0) 
			return _d;
		return getSum(data).multiply(new BigDecimal(1.00/data.size()));
	}
	
	/**
	 * 正态分布
	 * gaussian distribution
	 * f(x)=1/(√2π σ) exp⁡(-〖(x-μ)〗^2/(2σ^2 ))
	 *  [μ ̂-1σ ̂,μ ̂+1σ ̂]
	 * @return
	 */
	private static BigDecimal[] _gaussianDistribution(EachValues eachValues,MathExtendsEnum menum){
		MathContext mc = new MathContext(12, RoundingMode.HALF_DOWN);
		BigDecimal _stt = new BigDecimal(String.valueOf(Math.pow(Math.PI*2.0, 1/2.0)));
		_stt = _stt.multiply(eachValues.getVariance());
		//[μ ̂-1σ ̂,μ ̂+1σ ̂]
		BigDecimal _minX = eachValues.getAverage().subtract(eachValues.getVariance().multiply(menum.getValue()));
		BigDecimal _maxX = eachValues.getAverage().add(eachValues.getVariance().multiply(menum.getValue()));
		
		BigDecimal min =  _minX.subtract(eachValues.getAverage());
		BigDecimal max = _maxX.subtract(eachValues.getAverage());
		
		BigDecimal _minBefore = BigDecimal.ZERO.subtract(min.pow(2).divide(TWO.multiply(eachValues.getVariance(),mc),mc));
		BigDecimal _maxBefore = BigDecimal.ZERO.subtract(max.pow(2).divide(TWO.multiply(eachValues.getVariance(),mc),mc));
		
		BigDecimal _mint = new BigDecimal(String.valueOf(Math.exp(Double.valueOf(_minBefore.toString()))));
		BigDecimal _maxt = new BigDecimal(String.valueOf(Math.exp(Double.valueOf(_maxBefore.toString()))));
		
		BigDecimal _expMin = BigDecimal.ONE.divide(_stt,mc).multiply(_mint);
		BigDecimal _expMax = BigDecimal.ONE.divide(_stt,mc).multiply(_maxt);
		
		BigDecimal[] bary = {_expMin.divide(BigDecimal.ONE,mc),_expMax.divide(BigDecimal.ONE,mc)};
		
		return bary;
	}

	/**
	 *  正态分布
	 * gaussian distribution
	 * f(x)=1/(√2π σ) exp⁡(-〖(x-μ)〗^2/(2σ^2 ))
	 *  [μ ̂-1σ ̂,μ ̂+1σ ̂]
	 * @param data
	 * @return
	 */
	public static GaussianCalRtnTDO gaussianDistribution(List<BigDecimal> data) {
		EachValues es = new MathExtendsUtil.EachValues(data);
		if(null == es.getVariance()){
			return null;
		}
		GaussianCalRtnTDO rtn = new GaussianCalRtnTDO();
		
		rtn.setAverage(es.getAverage());
		rtn.setVariance(es.getVariance());
		
		BigDecimal[] bary = _gaussianDistribution(es,MathExtendsEnum.HIGH);
		rtn.setHighXMin(bary[0]);
		rtn.setHighXMax(bary[1]);
		
		bary = _gaussianDistribution(es,MathExtendsEnum.MIDDLE);
		rtn.setMiddleXMin(bary[0]);
		rtn.setMiddleXMax(bary[1]);
		
		bary = _gaussianDistribution(es,MathExtendsEnum.LOW);
		rtn.setLowXMin(bary[0]);
		rtn.setLowXMax(bary[1]);
		 
		return rtn;
	}
	
	
	/**
	 * 
	 * @author inner class
	 *
	 */
	public static class  EachValues{
		
		private BigDecimal _sum;
		
		private BigDecimal _average;
		
		private BigDecimal _squareSum;
		
		private BigDecimal _variance;

		private BigDecimal _varianceStd;

		private BigDecimal _varianceSq;
		
		public EachValues(List<BigDecimal> data){
			_sum = BigDecimal.ZERO;
			_average = BigDecimal.ZERO;
			_squareSum = BigDecimal.ZERO;
			_variance = BigDecimal.ZERO;
			_varianceSq = BigDecimal.ZERO;
			_varianceStd = BigDecimal.ZERO;
			if(data == null || data.size() == 0) 
				return;
			int xn  = data.size();
			for (BigDecimal _b : data) {
				if(_b!=null){
					_sum=_sum.add(_b);
					_squareSum =_squareSum.add(_b.pow(2));
				}
			}
			_average = _sum.multiply(new BigDecimal(String.valueOf(1.00/xn)));
			BigDecimal _tm = _squareSum.add(_average.pow(2).multiply(new BigDecimal(xn)));
			_tm = _tm.subtract(_average.multiply(new BigDecimal(2)).multiply(_sum));
			_variance = _tm.multiply(new BigDecimal(String.valueOf(1.00/xn)));
			double _tv = Double.valueOf(_variance.toString());
			_varianceStd = BigDecimal.valueOf(Math.sqrt(_tv)) ;
			_varianceSq = _variance.pow(2);
		}
		
		/**
		 * 总和
		 * @return
		 */
		public BigDecimal  getSum(){
			return _sum;
		}
		
		/**
		 * 均值
		 * @return
		 */
		public BigDecimal getAverage(){
			return _average;
		}
		
		/**
		 * 平方和
		 * @return
		 */
		public BigDecimal getSquareSum(){
			return _squareSum;
		}
		
		/**
		 * 方差
		 * @return
		 */
		public BigDecimal getVariance(){
			return _variance;
		}
		
		/**
		 * 标准方差
		 * @return
		 */
		public BigDecimal getVarianceStd(){
			return _varianceStd;
		}
		
		/**
		 * 方差平方
		 * @return
		 */
		public BigDecimal getVarianceSq(){
			return _varianceSq;
		}
	}
	
	/**
	 * Test
	 * @param args
	 */
	public static void main(String[] args) {
		List<BigDecimal> tData = new ArrayList<BigDecimal>();
		tData.add(new BigDecimal(58));
		tData.add(new BigDecimal(66));
		tData.add(new BigDecimal(60));
		tData.add(new BigDecimal(90));
		tData.add(new BigDecimal(84));
		tData.add(new BigDecimal(69));
		tData.add(new BigDecimal(89));
		tData.add(new BigDecimal(88));
		tData.add(new BigDecimal(98));
		tData.add(new BigDecimal(87));
		 
		EachValues es = new  MathExtendsUtil.EachValues(tData);
		
		System.out.println("\n\n");
		System.out.println("方差:"+es.getVariance());
		System.out.println("均值:"+es.getAverage());
		System.out.println("总和:"+es.getSum());
		System.out.println("\n\n");
		System.out.println(String.valueOf(Math.PI*2.0));
		System.out.println("\n\n --------------------------------------");
		
		
		GaussianCalRtnTDO rtn =  gaussianDistribution(tData);
		System.out.println("平均数: "+rtn.getAverage());
		System.out.println(" 方差: "+rtn.getVariance());
		
		System.out.println("x High: "+rtn.getHighXMax());
		System.out.println("i High: "+rtn.getHighXMin());
		
		System.out.println("x Midd: "+rtn.getMiddleXMax());
		System.out.println("i Midd: "+rtn.getMiddleXMin());
		
		System.out.println("x Low: "+rtn.getLowXMax());
		System.out.println("i Low: "+rtn.getLowXMin());
	}
	
}
